package system;

import java.io.*;
import java.security.*;
import java.util.Properties;

import javax.net.ssl.*;
import record.*;
import request.*;

/**
 * @author Sean Freitag
 * Client implementation to be instantiated by a user interface
 */
public class Client {
	
	/**
	 * Socket for sending information to the server
	 */
	private SSLSocket socket;
	
	/**
	 * Output stream for sending requests
	 */
	private ObjectOutputStream out;
	
	/**
	 * Input stream for receiving returns
	 */
	private ObjectInputStream in;
	
	/**
	 * Instantiates a new client
	 * @throws Exception
	 * Many different exceptions can be thrown, but if any are thrown, there is no reason to create the client
	 */
	public Client() throws Exception{
		initializeClientSocket();
		out = new ObjectOutputStream(socket.getOutputStream());
		in  = new ObjectInputStream(socket.getInputStream());
	}

	/**
	 * Initializes the client connection to the server
	 * @throws Exception
	 * If bad things happen, no need to create the client
	 */
	private void initializeClientSocket() throws Exception{
		
	    SSLSocketFactory factory = null;
		SSLContext ctx;
		KeyManagerFactory kmf;
		KeyStore ks;
		char[] passphrase = "passphrase".toCharArray();

		ctx = SSLContext.getInstance("TLS");
		kmf = KeyManagerFactory.getInstance("SunX509");
		ks = KeyStore.getInstance("JKS");

		Properties props = new Properties();
		try
		{
			props.load(new FileInputStream("resources/config.cfg"));
		}
		catch (IOException e)
		{
			throw new IOException("Properties file cannot be found or there was an error reading it.", e);
		}
		
//		ks.load(new FileInputStream("src/system/testkeys"), passphrase);
		ks.load(new FileInputStream(props.getProperty("keys")), passphrase);

		kmf.init(ks, passphrase);
		ctx.init(kmf.getKeyManagers(), null, null);

		factory = ctx.getSocketFactory();

		try
		{
	    	socket = (SSLSocket)factory.createSocket(props.getProperty("host"), 
	    			Integer.parseInt(props.getProperty("port")));
		}
		catch (NumberFormatException e)
		{
			throw new RuntimeException("Config file missing port value, or port value is invalid");
		}
	    
	    socket.startHandshake();		
	}
	
	/**
	 * Requests information from the server
	 * @param request
	 * Request for information
	 * @return
	 * Record requested, or null if no record matches the request
	 * @throws IOException
	 * If the socket fails
	 * @throws ClassNotFoundException
	 * If the class does not exist
	 */
	public Record sendRequest(Request request) throws IOException, ClassNotFoundException{
		out.reset();
		out.writeObject(request);
		return (Record) in.readObject();
	}

}
